/*
Author: Surpass-HC
Source: https://gitee.com/hxchuan000/clpc-1
Mail: surpass-hc@qq.com
*/
#include <lxShmOpt.h>
int shmOptInit(shmOptInfStc *shmPtr, key_t shmKey, queOptType shmSize, queOptType cfgRdrNbr, const char *lockFile)
{
    struct shmid_ds tmpShmInf;
    if (!shmPtr)
    {
        logerrorc("");
        return -1;
    }
    shmPtr->key = shmKey;
    do
    {
        // open lock file
        shmPtr->lockFd = open(lockFile, O_CREAT | O_RDWR, 0666);
        if (shmPtr->lockFd < 0)
        {
            printf("open lock file error!\n");
            break;
        }

        // open mem share by key
        shmPtr->shmFd = shmget(shmPtr->key, shmSize, IPC_CREAT | 0666);
        if (shmPtr->shmFd < 0)
        {
            logerrorc("%d,%d:%d,%s", shmPtr->key = shmKey, shmPtr->shmFd, errno, strerror(errno));
            break;
        }

        // get memery share size
        shmPtr->qasPtr = NULL;
        int tmpflag = shmctl(shmPtr->shmFd, IPC_STAT, &tmpShmInf);
        if (tmpflag < 0)
        {
            logerrorc("%d,%d,%d:%d,%s", shmPtr->key, shmPtr->shmFd, tmpflag, errno, strerror(errno));
            break;
        }
        size_t shmOptSize = tmpShmInf.shm_segsz;
        logdebugc("%d", (int)shmOptSize); // memery size
        if (shmSize != (uint32_t)shmOptSize)
        {
            logerrorc("%u != %u", (int32_t)shmSize, (int32_t)shmOptSize);
        }

        // get memery share ptr
        //__shmflg set SHM_RDONLY if readonly.
        shmPtr->qasPtr = (queOptStruct *)shmat(shmPtr->shmFd, NULL, 0); // SHM_RDONLY
        if ((long)shmPtr->qasPtr == -1 || !shmPtr->qasPtr)
        {
            logerrorc("%d,%d,%p:%d,%s", shmPtr->key, shmPtr->shmFd, shmPtr->qasPtr, errno, strerror(errno));
            break;
        }
        if (shmPtr->qasPtr->rdrNbr < 1)
        {
            logdebugc("init que");
            queOptInit(shmPtr->qasPtr, shmOptSize, cfgRdrNbr);
        }
        if (shmPtr->qasPtr->rdrNbr != cfgRdrNbr)
        {
            logerrorc("shm reader number:%d!=%d", shmPtr->qasPtr->rdrNbr, cfgRdrNbr);
        }
        return 0;
    } while (0);
    // fail point:
    shmOptFree(shmPtr);
    return -1;
}
int shmOptIsOk(shmOptInfStc *shmPtr)
{
    if (!(shmPtr && shmPtr->qasPtr && shmPtr->lockFd > 0 && shmPtr->shmFd > 0))
    {
        logerrorc("");
        return -1;
    }
    return 0;
}
queOptType shmOptWrite(shmOptInfStc *shmPtr, const uint8_t *buff, queOptType bsize)
{
    if (shmOptIsOk(shmPtr) < 0)
    {
        logerrorc("");
        return 0;
    }
    flock(shmPtr->lockFd, LOCK_EX);
    queOptWrite(shmPtr->qasPtr, buff, bsize);
    flock(shmPtr->lockFd, LOCK_UN);
    return bsize;
}
queOptType shmOptRead(shmOptInfStc *shmPtr, uint8_t rpin, uint8_t *buff, queOptType bsize)
{
    if (shmOptIsOk(shmPtr) < 0)
    {
        logerrorc("");
        return 0;
    }
    return queOptRead(shmPtr->qasPtr, rpin, buff, bsize);
}
int shmOptRestRcv(shmOptInfStc *shmPtr, uint8_t rdChnl)
{
    if (shmOptIsOk(shmPtr) < 0)
    {
        logerrorc("");
        return -1;
    }
    queOptResetR(shmPtr->qasPtr, rdChnl);
    return 0;
}
int shmOptFree(shmOptInfStc *shmPtr)
{
    if (!shmPtr)
    {
        logerrorc("");
        return -1;
    }
    // close lock file
    if (shmPtr->lockFd >= 0)
    {
        close(shmPtr->lockFd);
    }
    shmPtr->lockFd = -1;

    // disconnect memery share ptr
    if (shmPtr->qasPtr && (long)shmPtr->qasPtr != -1)
    {
        shmdt(shmPtr->qasPtr);
    }
    shmPtr->qasPtr = NULL;

    // disconnect memery share file
    if (shmPtr->shmFd >= 0)
    {
        shmctl(shmPtr->shmFd, IPC_RMID, NULL);
    }
    shmPtr->shmFd = -1;
    return 0;
}
